#include <boost/bind.hpp>
#include <boost/function.hpp>

#include <iostream>
#include <sstream>

#include "building_type.hpp"
#include "button.hpp"
#include "city_summary_dialog.hpp"
#include "foreach.hpp"
#include "formatter.hpp"
#include "grid_widget.hpp"
#include "image_widget.hpp"
#include "label.hpp"
#include "map_display.hpp"
#include "unit.hpp"
#include "unit_type.hpp"
#include "widget.hpp"

namespace game_dialogs {

city_summary_dialog::city_summary_dialog(map_display& m, world& w, city_ptr c)
  : dialog(800, 100, 224, 300), display_(m), world_(w), city_(c)
{
	init();
}

void city_summary_dialog::init()
{
	clear();
	using namespace gui;
	set_padding(10);

	const SDL_Color color = { 0xFF, 0xFF, 0xFF };

	int units_supported = city_->units_in_production().size();
	typedef std::pair<hex::location, unit_ptr> UnitPair;
	for(unit_map::const_iterator i = world_.units().begin(); i != world_.units().end(); ++i) {
		foreach(const_unit_ptr u, i->second) {
			if(u->home() == city_) {
				++units_supported;
			}
		}
	}

	int food_support = units_supported*2;
	const int food_support_cost = city_->market().can_buy_at(item_type::get("food"))*(food_support - city_->items_owned(item_type::get("food")));

	add_widget(widget_ptr(new label(city_->name(), color, 24)), 10, 20);

	add_widget(widget_ptr(new label(formatter() << "Population: " << city_->tile().citizens().size(), color)));

	std::map<std::string, int> deaths;
	int influence = 0;
	int food = 0;
	for(std::map<hex::location, int>::const_iterator i = city_->influence().begin(); i != city_->influence().end(); ++i) {
		const std::vector<citizen_ptr>& citizens = world_.map().get_tile(i->first)->citizens();
		influence += citizens.size();
		foreach(const citizen_ptr& c, citizens) {
			food += c->items_owned("food");
		}

		const std::vector<std::string>& causes_of_deaths = world_.map().get_tile(i->first)->causes_of_deaths();
		foreach(const std::string& cause, causes_of_deaths) {
			deaths[cause]++;
		}
	}

	add_widget(widget_ptr(new label(formatter() << "Influence: " << influence << " (" << food << " food)", color)));
	for(std::map<std::string, int>::const_iterator i = deaths.begin(); i != deaths.end(); ++i) {
		add_widget(widget_ptr(new label(formatter() << i->first << ": " << i->second, color)));
	}
	const int revenue = city_->revenue();
	const int expenses = city_->expenses() + food_support_cost;
	const int net = revenue - expenses;
	add_widget(widget_ptr(new label(formatter() << "Rev/Exp/Net: " << revenue << "/" << expenses << "/" << net, color)));
	add_widget(widget_ptr(new label(formatter() << "Supporting " << units_supported << ": " << food_support << " food (" << food_support_cost << ")", color)));

	std::ostringstream s;
	if(city_->projects().empty()) {
		s << "(no project) ";
	} else {
		project_ptr p = city_->projects().front();
		s << p->description() << " (" << p->labor_complete() << "/" << p->labor_required() << ") ";
	}

	s << "+" << city_->engineering_production() << "/turn";

	add_widget(widget_ptr(new label(s.str(), color)));

	boost::function<void ()> recruit_callback(boost::bind(&city_summary_dialog::recruit_unit_menu, this));
	button_ptr recruit_button(new button(widget_ptr(new label("Recruit", color)), recruit_callback));
	add_widget(recruit_button);

	button_ptr building_button(new button(widget_ptr(new label("Build Building", color)), boost::bind(&city_summary_dialog::build_menu, this)));
	add_widget(building_button);

	button_ptr improvement_button(new button(widget_ptr(new label("Build Improvement", color)), boost::bind(&map_display::build_terrain_improvement, &display_)));
	add_widget(improvement_button);

	boost::function<void ()> road_callback(boost::bind(&map_display::build_new_road, &display_));
	button_ptr build_road(new button(widget_ptr(new label("Build Road", color)), road_callback));
	add_widget(build_road);
}

void city_summary_dialog::recruit_unit_menu()
{
	SDL_Color color = {0xFF,0xFF,0xFF,0xFF};

	using namespace gui;
	gui::grid* grid = new gui::grid(2);
	grid->set_hpad(10);
	grid->allow_selection();
	grid->register_selection_callback(boost::bind(&city_summary_dialog::on_recruit, this, _1));
	std::vector<const_unit_type_ptr> units = city_->can_recruit();
	foreach(const_unit_type_ptr& u, units) {
		grid->add_col(widget_ptr(new image_widget(u->texture())));
		grid->add_col(widget_ptr(new label(u->description(), color)));
	}
	
	int mousex, mousey;
	SDL_GetMouseState(&mousex, &mousey);

	if(mousex+grid->width() > graphics::screen_width()) {
		mousey = graphics::screen_width() - grid->width();
	}

	if(mousey+grid->height() > graphics::screen_height()) {
		mousey = graphics::screen_height() - grid->height();
	}

	mousex -= x();
	mousey -= y();

	remove_widget(context_menu_);
	context_menu_.reset(grid);
	add_widget(context_menu_, mousex, mousey);
}

bool city_summary_dialog::handle_event(const SDL_Event& event, bool claimed)
{
	if(context_menu_) {
		gui::widget_ptr ptr = context_menu_;
		SDL_Event ev = event;
		normalize_event(&ev);
		return ptr->process_event(ev, claimed);
	}

	return dialog::handle_event(event, claimed);
}

void city_summary_dialog::on_recruit(int index)
{
	if(index >= 0) {
		std::vector<const_unit_type_ptr> units = city_->can_recruit();
		assert(index < units.size());
		display_.recruit_unit(units[index]);
	}

	remove_widget(context_menu_);
	context_menu_.reset();
}

void city_summary_dialog::build_menu()
{
	SDL_Color color = {0xFF,0xFF,0xFF,0xFF};

	using namespace gui;
	gui::grid* grid = new gui::grid(1);
	grid->set_hpad(10);
	grid->allow_selection();
	grid->register_selection_callback(boost::bind(&city_summary_dialog::on_build, this, _1));
	std::vector<const_building_type_ptr> buildings = city_->can_build();
	foreach(const_building_type_ptr& b, buildings) {
		grid->add_col(widget_ptr(new label(b->id(), color)));
	}
	
	int mousex, mousey;
	SDL_GetMouseState(&mousex, &mousey);

	if(mousex+grid->width() > graphics::screen_width()) {
		mousey = graphics::screen_width() - grid->width();
	}

	if(mousey+grid->height() > graphics::screen_height()) {
		mousey = graphics::screen_height() - grid->height();
	}

	mousex -= x();
	mousey -= y();

	remove_widget(context_menu_);
	context_menu_.reset(grid);
	add_widget(context_menu_, mousex, mousey);
}

void city_summary_dialog::on_build(int index)
{
	if(index >= 0) {
		std::vector<const_building_type_ptr> buildings = city_->can_build();
		assert(index < buildings.size());
		display_.build_building(buildings[index]);
		clear();
		init();
	}
	
	remove_widget(context_menu_);
	context_menu_.reset();
}
}
